import logging
from django.core.exceptions import ValidationError, PermissionDenied
from django.db import DatabaseError
from redis.exceptions import RedisError
from rest_framework.views import exception_handler as drf_exception_handler
from rest_framework.response import Response
from rest_framework import status
from rest_framework.exceptions import NotAuthenticated, AuthenticationFailed

logger = logging.getLogger('django')

def custom_exception_handler(exc, context):
    """
    自定义异常处理
    :param exc: 异常
    :param context: 抛出异常的上下文
    :return: Response响应对象
    """
    # 调用drf框架原生的异常处理方法
    response = drf_exception_handler(exc, context)

    # 如果response为空，则意味着异常不是由REST framework处理的
    if response is None:
        view = context['view']
        if isinstance(exc, DatabaseError) or isinstance(exc, RedisError):
            # 数据库异常
            logger.error('[%s] %s' % (view, exc))
            response = Response({'message': '服务器内部错误'}, status=status.HTTP_507_INSUFFICIENT_STORAGE)
        elif isinstance(exc, ValidationError):
            # 验证异常
            logger.error('[%s] %s' % (view, exc))
            response = Response({'message': '数据验证错误', 'detail': str(exc)}, status=status.HTTP_400_BAD_REQUEST)
        elif isinstance(exc, PermissionDenied):
            # 权限拒绝异常
            logger.error('[%s] %s' % (view, exc))
            response = Response({'message': '权限不足'}, status=status.HTTP_403_FORBIDDEN)
        elif isinstance(exc, NotAuthenticated) or isinstance(exc, AuthenticationFailed):
            # 认证异常
            logger.error('[%s] %s' % (view, exc))
            response = Response({'message': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)
        else:
            # 处理其他未捕获的异常
            logger.error('[%s] %s' % (view, exc))
            response = Response({
                'detail': 'An unexpected error occurred.',
                'message': str(exc)
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
    else:
        # 在这里可以自定义返回的内容
        if response.status_code == 404:
            response.data = {
                'detail': 'Resource not found.',
                'message': str(exc)
            }

        if response.status_code == 500:
            response.data = {
                'detail': 'A server error occurred.',
                'message': str(exc)
            }

    return response
